package com.lokiy.kit.widget

import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.widget.FrameLayout
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Job

/**
 * 横向滚动弹幕
 * @author Lokiy
 * @date 2023-07-21 16:43
 */
class LinearDanMu : View {

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)


    private val adapters: MutableList<RecyclerView.Adapter<RecyclerView.ViewHolder>> = mutableListOf()
    private val speeds: MutableList<Int> = mutableListOf()

    private val trackCount: Int
        get() = adapters.size

    private var trackHeight: Int = 0
    private val trackSpace = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12f, context.resources.displayMetrics).toInt()
    private val frameLayout = FrameLayout(context)
    private val cacheViewHolders: MutableMap<Int, MutableList<RecyclerView.ViewHolder>> = hashMapOf()
    private val steps = mutableListOf<Int>()
    private val visibleStartPositions = mutableListOf<Int>()
    private val visibleEndPositions = mutableListOf<Int>()
    private val emptyWidths = mutableListOf<Int>()

    private val usedViewHolders: MutableMap<String, RecyclerView.ViewHolder> = hashMapOf()
    private var job: Job? = null
    var isOnStart = false
        private set

    fun setup(vararg trackItem: TrackItem) {
        adapters.clear()
        speeds.clear()
        visibleStartPositions.clear()
        visibleEndPositions.clear()
        trackItem.forEach {
            adapters.add(it.adapter)
            speeds.add(it.speed)
            visibleStartPositions.add(0)
            visibleEndPositions.add(0)
            emptyWidths.add(0)
            steps.add(0)
        }
        start()
    }

    fun start() {
        if (isOnStart) return//@launch
        isOnStart = true
        postInvalidate()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        job?.cancel()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        if (job != null || isOnStart) {
            start()
        }
    }

    fun stop() {
        isOnStart = false
        job?.cancel()
        job = null
    }

    data class TrackItem(val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>, val speed: Int)

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        drawDanmu(canvas ?: return)
    }

    fun getVisiblePosition(track: Int): Pair<Int, Int> {
        return if (track < visibleStartPositions.size) {
            var firstVisibleItemPosition: Int = visibleStartPositions[track]
            var lastVisibleItemPosition: Int = visibleEndPositions[track]
            val fix = (lastVisibleItemPosition - firstVisibleItemPosition) / 3
            firstVisibleItemPosition += fix
            lastVisibleItemPosition -= fix
            firstVisibleItemPosition to lastVisibleItemPosition
        } else {
            0 to 0
        }
    }

    fun getAdapter(track: Int) = adapters.getOrNull(track)

    private fun drawDanmu(canvas: Canvas?) {
        canvas ?: return

        for (track in 0 until trackCount) {
            val adapter = adapters[track]
            var position = visibleStartPositions[track]
            var tempWidth = 0
            var firstItemWidth = 0
            var firstLeft = 0
            while (true) {
                val itemViewType = adapter.getItemViewType(position)
                val viewHolder: RecyclerView.ViewHolder =
                    usedViewHolders["${track}_$position"] ?: (cacheViewHolders[itemViewType]?.removeFirstOrNull() ?: adapter.createViewHolder(
                        frameLayout, itemViewType
                    )).also {
                        usedViewHolders["${track}_$position"] = it
                        adapter.bindViewHolder(it, position)
                        val view: View = it.itemView
                        view.measure(0, 0)
                        if (trackHeight == 0) {
                            trackHeight = view.measuredHeight
                            requestLayout()
                        }
                        if (view.alpha == 1f) {
                            view.layout(0, 0, view.measuredWidth, view.measuredHeight)
                        }
                    }
                val view: View = viewHolder.itemView
                val dx = steps[track] + tempWidth
                val left = width + dx
                val childWidth = view.measuredWidth
                val dy = track * (trackHeight + trackSpace)
                val layoutParams = view.layoutParams

                if (view.alpha == 1f) {
                    canvas.translate(left.toFloat(), dy.toFloat())
                    view.draw(canvas)
                    canvas.translate(-left.toFloat(), -dy.toFloat())
                }

                tempWidth += childWidth + if (layoutParams is MarginLayoutParams) layoutParams.marginStart + layoutParams.marginEnd else 0
                if (firstItemWidth == 0) {
                    firstItemWidth = tempWidth
                    firstLeft = left
                }
                if (left + childWidth > width) {
                    visibleEndPositions[track] = position
                    if (firstLeft + firstItemWidth < 0) {
                        val viewHolders =
                            cacheViewHolders[itemViewType] ?: mutableListOf<RecyclerView.ViewHolder>().also { cacheViewHolders[itemViewType] = it }
                        usedViewHolders.remove("${track}_${visibleStartPositions[track]}")?.let { viewHolders.add(it) }
                        visibleStartPositions[track] += 1
                        emptyWidths[track] += firstItemWidth
                        steps[track] += firstItemWidth
                    }
                    break
                }
                position++
            }
            steps[track] -= speeds[track]
        }
        if (isOnStart) {
            invalidate()
        }
    }

    fun findViewHolderForAdapterPosition(track: Int, position: Int): RecyclerView.ViewHolder? {
        return usedViewHolders["${track}_${position}"]
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (trackHeight != 0) {
            setMeasuredDimension(
                getDefaultSize(suggestedMinimumWidth, widthMeasureSpec),
                (trackHeight + trackSpace) * trackCount - trackSpace + paddingTop + paddingBottom
            )
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }

    }
}